﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Spanner
{
    public abstract class Act : ITerm
    {
        void ITerm.Write(Context ctxt, JSorHtml what) { throw new NotImplementedException(); }

        IEnumerable<IVar> ITerm.Dependencies() { throw new NotImplementedException(); }

        public static implicit operator Act(Expr<Act> e)
        {
            return new JSAct("#", e);
        }
    }

    internal class FmtAct : Act, ITerm
    {
        internal string Desc; // Just for documentation.

        internal ITerm[] Children;

        internal FmtAct(string desc, params ITerm[] children) { Desc = desc; Children = children; }

        void ITerm.Write(Context ctxt, JSorHtml what)
        {
            foreach (var x in Children) x.Write(ctxt, what);
        }

        IEnumerable<IVar> ITerm.Dependencies()
        {
            return Children.SelectMany(x => (x is IVar) ? new IVar[] { (IVar)x } : ((ITerm)x).Dependencies());
        }
    }

    internal class JSAct : Act, ITerm
    {
        internal FmtOneLiner Fmt;

        internal JSAct(string fmt, params ITerm[] args)
        {
            Fmt = new FmtOneLiner { Fmt = fmt, Children = args };
        }

        void ITerm.Write(Context ctxt, JSorHtml what)
        {
            if (what == JSorHtml.JS) ctxt.WriteIndentation();
            ctxt.WriteTerm((ITerm)Fmt, what);
            ctxt.WritePlain(";");
            if (what == JSorHtml.JS) ctxt.WriteLine();
        }

        IEnumerable<IVar> ITerm.Dependencies() { return ((ITerm)Fmt).Dependencies(); }
    }

    internal class VerbatimJavaScriptAct : Act, ITerm
    {
        internal string JS;

        void ITerm.Write(Context ctxt, JSorHtml what)
        {
            ctxt.WritePlain(JS);
        }

        IEnumerable<IVar> ITerm.Dependencies() { yield break; }
    }

}
